package com.xiaode.controller.app.teacher.gradeClass;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.jfinal.aop.Before;
import com.jfinal.kit.Kv;
import com.jfinal.kit.Ret;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Page;
import com.jfinal.plugin.activerecord.Record;
import com.jfinal.plugin.activerecord.tx.Tx;
import com.jfinal.plugin.redis.Cache;
import com.jfinal.plugin.redis.Redis;
import com.xiaode.common.constant.Const;
import com.xiaode.common.model.*;
import com.xiaode.exce.EnumError;

import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

public class MyGradeClassService {

    /**
     * 查询班级学生列表
     * @param admin 当前教师
     * @param page
     * @param limit
     * @param date 日期
     * @param clasId 班级
     * @return
     */
    public Ret findStduentsPage(Admin admin, Integer page, Integer limit, Date date, Integer clasId) {
        Set<Integer> clasIds = admin.get("frameworkPermission");
        if (!clasIds.contains(clasId)) {
            return Ret.fail().set("error", EnumError.NOT_HAVE_AUTHORITY.getObj());
        }
        Page<Student> studentPage = Student.dao.paginate(page, limit, "SELECT id,number,name,zScore,accountId,studentNo", "FROM student WHERE clasId = ? AND isDele = 0 ", clasId);
        List<Student> list = studentPage.getList();
        Cache redis = Redis.use();
        DateTime startTime = DateUtil.beginOfDay(date);
        DateTime endTime = DateUtil.endOfDay(date);
        LocalDateTime start = DateUtil.toLocalDateTime(startTime);
        LocalDateTime end = DateUtil.toLocalDateTime(endTime);
        List<StudentAbsence> absenceList = StudentAbsence.dao.find("SELECT * FROM student_absence WHERE absence_date BETWEEN ? AND ? AND student_clas = ?", start, end, clasId);
        Map<Integer, Integer> map = absenceList.stream().collect(Collectors.toMap(StudentAbsence::getStudentAccountId, StudentAbsence::getId));
        for (Student student : list) {
            Student o = redis.get(Const.user.Student + student.getId());
            Long timestamp = o.getLong("lastLoginTimestamp");
            if (timestamp == null || timestamp == 0) {
                student.setLastLoginTime(null);
            } else {
                student.setLastLoginTime(new Date(timestamp).toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
            }
            ScoreRank sr = ScoreRank.dao.findFirst("SELECT * FROM score_rank WHERE studentId = ? AND MONTH(`addTime`) = MONTH(?)", student.getId(), date);
            student.put("score", BeanUtil.isEmpty(sr) ? 0 : sr.getScore());
            student.put("isLogin",student.getInt("score") == 0 ? "否":"是");
            Integer integer = map.get(student.getAccountId());
            student.put("absence",integer != null);
            student.put("absenceId",integer);
        }

        return Ret.ok(clasId, studentPage);
    }

    /**
     * 查询学生信息
     * @param admin
     * @param page
     * @param limit
     * @param date
     * @return
     */
    public Ret findStduents(Admin admin, Integer page, Integer limit, Date date) {
    	Set<Integer> clasIds = admin.get("frameworkPermission");
        Map<Integer, Page<Student>> map = new HashMap<Integer, Page<Student>>();
        for (Integer clasId : clasIds) {
            Page<Student> studentPage = Student.dao.paginate(page, limit, "SELECT id,number,name,zScore,accountId", "FROM student WHERE clasId = ? AND isDele = 0", clasId);
            List<Student> list = studentPage.getList();
            Cache redis = Redis.use();
            for (Student student : list) {
                Integer zScore = student.getZScore();
                student.put("isLogin", zScore == 0 ? "否" : "是");
                Student o = redis.get(Const.user.Student + student.getId());
                Long timestamp = o.getLong("lastLoginTimestamp");
                if (timestamp == 0) {
                    student.setLastLoginTime(null);
                } else {
                    student.setLastLoginTime(new Date(timestamp).toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
                }
                //添加分数
//                DateTime dt = DateUtil.beginOfMonth(date);
//                dt = dt.offset(DateField.HOUR_OF_DAY, -24);
//                System.out.println(dt.toJdkDate());
                ScoreRank sr = ScoreRank.dao.findFirst("SELECT * FROM score_rank WHERE studentId = ? AND MONTH(`addTime`) = MONTH(?)", student.getId(), date);
                student.put("score", BeanUtil.isEmpty(sr) ? 0 : sr.getScore());
            }

            map.put(clasId, studentPage);
        }
        //TODO 论坛数据

        return Ret.ok("students", map).set("forumData", null);
    }

    /**
     * 查询年级信息
     * @param admin
     * @return
     */
    public Ret findGradeInfo(Admin admin) {

        Map<String, List<Record>> map = new HashMap<String, List<Record>>();
        //领域分布
        List<Record> rs = Db.template("domainDistribution").find();
        rs = rs.stream().filter(record -> record.getStr("label") != null).collect(Collectors.toList());

        int stratum = admin.get("stratum");
        if (stratum == 0) {
            return Ret.ok("schoolYearData", map).set("domain", rs);
        } else if (stratum == 1) {
            List<OrgGrade> ogs = OrgGrade.dao.find("SELECT * FROM org_grade WHERE isRoot = 0");
            for (OrgGrade og : ogs) {
                List<OrgClass> ocs = OrgClass.dao.find("SELECT id FROM org_class WHERE adminGradeId = ?", og.getId());
                if (ocs.size() == 0) {
                    continue;
                }
                Kv kv = Kv.create().setIfNotNull("ocs", ocs);
                List<Record> record = Db.template("clasSumScore", kv).find();
                map.put(og.getName(), record);
            }
        } else if (stratum == 2) {
            List<OrgAdmin> oas = OrgAdmin.dao.find("SELECT stratumId FROM org_admin WHERE stratum = 2 AND adminId = ?", admin.getId());
            for (OrgAdmin oa : oas) {
                List<OrgGrade> ogs = OrgGrade.dao.find("SELECT * FROM org_grade WHERE id = ?", oa.getStratumId());
                for (OrgGrade og : ogs) {
                    List<OrgClass> ocs = OrgClass.dao.find("SELECT id FROM org_class WHERE adminGradeId = ?", og.getId());
                    if (ocs.size() == 0) {
                        continue;
                    }
                    Kv kv = Kv.create().setIfNotNull("ocs", ocs);
                    List<Record> record = Db.template("clasSumScore", kv).find();
                    map.put(og.getName(), record);
                }
            }
        } else if (stratum == 3) {
            return Ret.ok("schoolYearData", map).set("domain", rs);
        }
        return Ret.ok("schoolYearData", map).set("domain", rs);
    }

    /**
     * 根据名称搜索
     */
    public Ret findStduentByName(Admin admin, String name,Date date) {
        Cache redis = Redis.use();
        Set<Integer> clasIds = admin.get("frameworkPermission");
        LocalDateTime time = DateUtil.toLocalDateTime(date);
        LocalDateTime start = time.with(LocalTime.MIN);
        LocalDateTime end = time.with(LocalTime.MAX);
        List<Student> studentList = Student.dao.find("SELECT id,number,name,zScore,avatarUrl,sex,clasId,accountId,studentNo FROM student WHERE name like concat('%',?,'%') AND isDele = 0", name);
        ArrayList<Student> students = new ArrayList<>();
        for (Student student : studentList) {
            if (clasIds.contains(student.getClasId())) {
                Student o = redis.get(Const.user.Student + student.getId());

                Long timestamp = o.getLong("lastLoginTimestamp");
                if (timestamp == 0) {
                    student.setLastLoginTime(null);
                } else {
                    student.setLastLoginTime(new Date(timestamp).toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
                }
                ScoreRank sr = ScoreRank.dao.findFirst("SELECT * FROM score_rank WHERE studentId = ? AND MONTH(`addTime`) = MONTH(?)", student.getId(), date);
                student.put("score", BeanUtil.isEmpty(sr) ? 0 : sr.getScore());
                student.put("isLogin", student.getInt("score") == 0 ? "否" : "是");
                StudentAbsence studentAbsence = StudentAbsence.dao.findFirst("SELECT * FROM student_absence WHERE student_account_id = ? AND absence_date BETWEEN ? AND ?", student.getAccountId(), start, end);
                student.put("absence", studentAbsence != null);
                if (BeanUtil.isNotEmpty(studentAbsence)) {
                    student.put("reason", studentAbsence.getReason());
                }
                students.add(student);
            }
        }
        return Ret.ok().set("students",students);
    }

    /**
     * 教师提交班级缺勤记录
     * @param admin
     * @param clasId
     * @param date
     * @return
     */
    @Before(Tx.class)
    public Ret submitClassAbsence(Admin admin, Integer clasId, Date date)throws Exception {
        LocalDateTime time = DateUtil.toLocalDateTime(date);
        LocalDateTime start = time.with(LocalDateTime.MIN);
        LocalDateTime end = time.with(LocalDateTime.MAX);
        //查询当前教师是否该班班主任
        OrgAdmin orgAdmin = OrgAdmin.dao.findFirst("SELECT * FROM org_admin WHERE adminId = ? AND stratumId = ? AND stratum = 3", admin.getId(), clasId);
        if (BeanUtil.isEmpty(orgAdmin)) {
            return Ret.fail().set("error", EnumError.NOT_LEADER_CLASS.getObj());
        }
        //查询当天记录是否已经提交过
        ClasSubmit first = ClasSubmit.dao.findFirst("SELECT * FROM clas_submit WHERE clas_id = ? AND submit_date BETWEEN ? AND ?", clasId, start, end);
        if (BeanUtil.isNotEmpty(first)){
            return Ret.fail().set("error", EnumError.HAVE_SUBMIT_LOG.getObj());
        }
        ClasSubmit clasSubmit = new ClasSubmit();
        LocalDateTime dateTime = time.with(LocalTime.of(1, 0));
        clasSubmit.setSubmitDate(dateTime);
        clasSubmit.setClasId(clasId);
        clasSubmit.setTeacherId(admin.getId());
        clasSubmit.setSubmitDate(dateTime);
        clasSubmit.save();
//        List<StudentAbsence> list = absenceDTOS.stream().map(studentAbsenceDTO -> {
//            StudentAbsence studentAbsence = new StudentAbsence();
//            studentAbsence.setStudentId(studentAbsenceDTO.getStuId());
//            studentAbsence.setReason(studentAbsenceDTO.getReason());
//            studentAbsence.setAbsenceDate(dateTime);
//            studentAbsence.setClasSubmitId(clasSubmit.getId());
//            return studentAbsence;
//        }).collect(Collectors.toList());
//        Db.batchSave(list,list.size());
        return Ret.ok();
    }


    /**
     * 教师确认学生缺席
     * @param admin
     * @param date
     * @param accountId
     * @return
     */
    public Ret studentAbsence(Admin admin, Date date, Integer accountId,String reason) {

        LocalDateTime localDateTime = DateUtil.toLocalDateTime(date);
        LocalDateTime start = localDateTime.with(LocalTime.MIN);
        LocalDateTime end = localDateTime.with(LocalTime.MAX);
        LocalDateTime time = localDateTime.with(LocalTime.of(1, 0));

        StudentAbsence studentAbsence = new StudentAbsence();
        studentAbsence.setAbsenceDate(time);
        studentAbsence.setStudentAccountId(accountId);
        studentAbsence.setTeacherAccountId(admin.getAccountId());
        studentAbsence.setReason(reason);
        Cache redis = Redis.use();
        Record rec = redis.hget(Const.user.AccountIdInfo, accountId);
        Integer id = rec.getInt("id");
        Student o = redis.get(Const.user.Student + id);
        studentAbsence.setStudentClas(o.getClasId());
        Record record = redis.hget(Const.user.AccountIdInfo, accountId);
        if (BeanUtil.isEmpty(record)){
            return Ret.fail().set("error",EnumError.USER_NULL.getObj());
        }
        OrgAdmin orgAdmin = OrgAdmin.dao.findFirst("SELECT * FROM org_admin WHERE adminId = ? AND stratumId = ? AND stratum = 3", admin.getId(), o.getClasId());
        if (BeanUtil.isEmpty(orgAdmin)) {
            return Ret.fail().set("error", EnumError.NOT_LEADER_CLASS.getObj());
        }
        //查询缺勤记录 ,如果已经提交过,不能设置学生缺勤
        ClasSubmit clasSubmit = ClasSubmit.dao.findFirst("SELECT * FROM clas_submit WHERE clas_id = ? AND submit_date BETWEEN ? AND ?", o.getClasId(), start, end);
        if (BeanUtil.isNotEmpty(clasSubmit)) {
            return Ret.fail().set("error", EnumError.HAVE_SUBMIT_LOG.getObj());
        }
//        Integer id = record.getInt("id");
        Integer userType = record.getInt("userType");
        if (userType != Const.UserType.student){
            return Ret.fail().set("error",EnumError.PARAMETER_ERROR.getObj());
        }
        studentAbsence.save();
        return Ret.ok();
    }

    /**
     * 取消学生缺席
     * @param admin
     * @return
     */
    public Ret cancelStudentAbsence(Admin admin, Integer accountId,Date date) {
        LocalDateTime time = DateUtil.toLocalDateTime(date);
        LocalDateTime startTime = time.with(LocalTime.MIN);
        LocalDateTime endTime = time.with(LocalTime.MAX);
        StudentAbsence studentAbsence = StudentAbsence.dao.findFirst("SELECT * FROM student_absence WHERE student_account_id = ? AND absence_date BETWEEN ? AND ?", accountId, startTime, endTime);
        Integer studentClas = studentAbsence.getStudentClas();
        OrgAdmin orgAdmin = OrgAdmin.dao.findFirst("SELECT * FROM org_admin WHERE adminId = ? AND stratumId = ? AND stratum = 3", admin.getId(),studentClas);
        if (BeanUtil.isEmpty(orgAdmin)) {
            return Ret.fail().set("error", EnumError.NOT_LEADER_CLASS.getObj());
        }
        //查询当天的学生记录是否已经 提交过,如果提交过,则不能取消学生缺勤记录
        ClasSubmit clasSubmit = ClasSubmit.dao.findFirst("SELECT * FROM clas_submit WHERE clas_id = ? AND submit_date BETWEEN ? AND ?", studentClas, startTime, endTime);
        if (BeanUtil.isNotEmpty(clasSubmit)) {
            return Ret.fail().set("error", EnumError.HAVE_SUBMIT_LOG.getObj());
        }
        studentAbsence.delete();
        return Ret.ok();
    }


    /**
     * 卫生教师查询
     * @param admin
     * @param name
     * @param date
     * @return
     */
    public Ret heathFindStudent(Admin admin, String name, Date date) {
        if (!admin.getHealtherTeacher()) {
            return Ret.fail().set("error",EnumError.NOT_HEATHER_TEACHER.getObj());
        }
        Cache redis = Redis.use();
        LocalDateTime time = DateUtil.toLocalDateTime(date);
        LocalDateTime end = time.with(LocalTime.MAX);
        LocalDateTime start = time.with(LocalTime.MIN);
        List<Record> students = Db.find("SELECT stu.id,stu.number,stu.name,stu.zScore,stu.avatarUrl,stu.sex,stu.clasId,stu.studentNo,sa.reason,sa.id absenId FROM student_absence sa INNER JOIN student stu ON sa.student_account_id = stu.accountId AND sa.absence_date BETWEEN ? AND ? WHERE stu.name like concat('%',?,'%') AND stu.isDele = 0",start, end,name);
        for (Record student : students) {
            Student o = redis.get(Const.user.Student + student.getInt("id"));

            Long timestamp = o.getLong("lastLoginTimestamp");
            if (timestamp == 0) {
                student.put("lastLoginTime",null);
            } else {
                student.put("lastLoginTime",DateUtil.toLocalDateTime(new Date(timestamp)));
            }
            ScoreRank sr = ScoreRank.dao.findFirst("SELECT * FROM score_rank WHERE studentId = ? AND MONTH(`addTime`) = MONTH(?)", student.getInt("id"), date);
            student.put("score", BeanUtil.isEmpty(sr) ? 0 : sr.getScore());
            student.put("isLogin", student.getInt("score") == 0 ? "否" : "是");
        }
        return Ret.ok().set("students",students);
    }


    public Ret findAbsence(Admin admin, Date date, Integer page, Integer limit) throws Exception {
        if (!admin.getHealtherTeacher()) {
            return Ret.fail().set("error",EnumError.NOT_HEATHER_TEACHER.getObj());
        }
        LocalDateTime localDateTime = DateUtil.toLocalDateTime(date);
        LocalDateTime startDay = localDateTime.with(LocalTime.MIN);
        LocalDateTime endDay = localDateTime.with(LocalTime.MAX);
        List<Integer> clasIdList = ClasSubmit.dao.find("SELECT * FROM clas_submit WHERE submit_date BETWEEN ? AND ?", startDay, endDay).stream().map(ClasSubmit::getClasId).collect(Collectors.toList());
        //查询总人数
        if (clasIdList.isEmpty()) {
            return Ret.ok().set("sum", 0).set("page", null);
        }
        Cache redis = Redis.use();
        Kv kv = Kv.by("clasIdList", clasIdList);
        Record num = Db.template("findClsStudentSum", kv).findFirst();
        Integer sum = num.getInt("sum");
        //分页查询学生缺勤记录
        Page<StudentAbsence> absencePage = StudentAbsence.dao.paginate(page, limit, "SELECT * ", " FROM student_absence WHERE absence_date BETWEEN ? AND ? ORDER BY student_clas", startDay, endDay);
        List<StudentAbsence> list = absencePage.getList();
        //查询学生信息
        for (StudentAbsence studentAbsence : list) {
            Record rec = redis.hget(Const.user.AccountIdInfo, studentAbsence.getStudentAccountId());
            Integer id = rec.getInt("id");
            Student o = redis.get(Const.user.Student + id);
            studentAbsence.put("name", o.getName());
            studentAbsence.put("sex", o.getSex());
            studentAbsence.put("number", o.getNumber());
            studentAbsence.put("studentNo",o.getStudentNo());
        }
        return Ret.ok().set("sum", sum).set("page", absencePage);
    }
}
